/*!
 Temelia - Stack implementation source file.

 Copyright (C) 2008, 2009 Ceata (http://ceata.org/proiecte/temelia).

 @author Dascalu Laurentiu

 This program is free software; you can redistribute it and
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 3
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "include/stack.h"
#include "include/vector.h"
#include "include/common.h"
#include <stdlib.h>

struct _stack_t
{
	vector_t data;
};

stack_t stack_new(int capacity)
{
	stack_t s;

	_ASSERT(capacity, <=, 0, INVALID_INPUT, NULL);

	s = (struct _stack_t *) _new(sizeof(struct _stack_t));

	_ASSERT(s, ==, NULL, NULL_POINTER, NULL);

	s->data = vector_new(capacity);

	if (s->data == NULL)
	{
		_delete(s);
		return NULL;
	}

	return s;
}

void stack_delete(stack_t s)
{
	_ASSERT(s, ==, NULL, NULL_POINTER,);

	vector_delete(s->data);
	_delete(s);
}

int stack_get_size(stack_t s)
{
	_ASSERT(s, ==, NULL, NULL_POINTER, -1);

	return vector_get_size(s->data);
}

int stack_get_capacity(stack_t s)
{
	_ASSERT(s, ==, NULL, NULL_POINTER, -1);

	return vector_get_capacity(s->data);
}

int stack_get_capacity_increment(stack_t s)
{
	_ASSERT(s, ==, NULL, NULL_POINTER, -1);

	return vector_get_capacity_increment(s->data);
}

void *stack_get_internal_representation(stack_t s)
{
	return s->data;
}

int stack_is_empty(stack_t s)
{
	_ASSERT(s, ==, NULL, NULL_POINTER, -1);

	return vector_is_empty(s->data);
}

int stack_is_full(stack_t s)
{
	_ASSERT(s, ==, NULL, NULL_POINTER, -1);

	return vector_is_full(s->data);
}

void stack_push(stack_t s, void *x)
{
	_ASSERT(s, ==, NULL, NULL_POINTER,);

	vector_push_back(s->data, x);
}

void stack_pop(stack_t s)
{
	_ASSERT(s, ==, NULL, NULL_POINTER,);
	_ASSERT(vector_get_size(s->data), <=, 0, EMPTY,);

	vector_set_size(s->data, vector_get_size(s->data) - 1);
}

void *stack_top(stack_t s)
{
	_ASSERT(s, ==, NULL, NULL_POINTER, NULL);
	_ASSERT(vector_get_size(s->data), <=, 0, EMPTY, NULL);

	return vector_get_key_at(s->data, vector_get_size(s->data) - 1);
}

void stack_set_capacity_increment(stack_t s, int capacity_increment)
{
	_ASSERT(s, ==, NULL, NULL_POINTER,);

	vector_set_capacity_increment(s->data, capacity_increment);
}

void stack_iterate(stack_t s, void key_handler(void *key, void *context),
		void *context, int order)
{
	int i, size;

	_ASSERT(s, ==, NULL, NULL_POINTER,);
	_ASSERT(key_handler, ==, NULL, NULL_POINTER,);

	size = vector_get_size(s->data);

	if (order == -1)
		for (i = 0; i < size; i++)
			key_handler(vector_get_key_at(s->data, i), context);
	else if (order == 1)
		for (i = size - 1; i >= 0; i--)
			key_handler(vector_get_key_at(s->data, i), context);
	else
		temelia_errno = INVALID_INPUT;
}
